package com.cmc.cloud.cmclink.doc.api.document;

import com.cmc.cloud.cmclink.doc.api.document.emums.*;
import com.cmc.cloud.cmclink.doc.api.document.rep.*;
import com.cmc.cloud.cmclink.doc.api.document.req.EqmBlInfoRespDto;
import com.cmc.cloud.cmclink.doc.api.document.req.EqmVoyInfoReqDto;
import com.cmc.cloud.cmclink.doc.api.document.req.so.EqmInfoSearchReqDto;
import com.cmc.cloud.cmclink.doc.constants.errorconstant.EqmErrorConstant;
import com.cmc.cloud.cmclink.doc.entity.*;
import com.cmc.cloud.cmclink.doc.mapper.*;
import com.cmc.cloud.cmclink.doc.rpcservice.MktService;
import com.cmc.cloud.cmclink.doc.rpcservice.VoyScheduleService;
import com.cmc.cloud.cmclink.doc.util.CostChargeUtil;
import com.cmc.cloud.cmclink.mkt.dto.rate.CalFrtRateUnitReqVo;
import com.cmc.cloud.cmclink.mkt.dto.sc.FreeTimeReqVo;
import com.cmc.cloud.cmclink.svl.api.base.req.BargeQueryReqDTO;
import com.cmes.framework.common.exception.ErrorCode;
import com.cmes.framework.common.exception.util.ServiceExceptionUtil;
import com.cmes.framework.common.pojo.CommonResult;
import com.cmes.framework.mybatis.core.query.LambdaQueryWrapperX;
import jodd.util.StringUtil;
import org.apache.commons.collections.CollectionUtils;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.RestController;

import javax.annotation.Resource;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.util.*;
import java.util.stream.Collectors;

import static java.util.stream.Collectors.groupingBy;
import static java.util.stream.Collectors.toList;

/**
 * @author lzp
 */
@RestController
@Validated
public class EquipmentApiImpl implements EquipmentApi {

    @Resource
    private SoMapper soMapper;

    @Resource
    private SoForecastMapper soForecastMapper;

    @Resource
    private RequirementsMapper requirementsMapper;

    @Resource
    private SoScnMapper soScnMapper;

    @Resource
    private BlnoMapper blnoMapper;

    @Resource
    private BlnoScnMapper blnoScnMapper;

    @Resource
    private BlnoCntrMapper blnoCntrMapper;

    @Resource
    private MktService mktService;

    @Resource
    private CostChargeUtil costChargeUtil;

    @Resource
    private BlnoVslvoyMapper blnoVslvoyMapper;

    private static final String TBA = "TBA";

    private static final String BARGE_ERROR = "驳船船名航次未维护";

    private static final String SCHEDULE_ERROR = "驳船获取船期时间失败";

    @Resource
    private VoyScheduleService voyScheduleService;

    @Resource
    private BlnoCargoMapper blnoCargoMapper;

    @Override
    public CommonResult<List<EqmInfoSearchRespDto>> searchExForecastInfo(EqmInfoSearchReqDto eqmInfoSearchReqDto) {
        if (StringUtil.isEmpty(eqmInfoSearchReqDto.getPolCode())) {
            throw ServiceExceptionUtil.exception(EqmErrorConstant.EQM_POL_NOT_ALLOW_NULL);
        }
        List<EqmInfoSearchRespDto> eqmInfoSearchRespDtos = soMapper.rpcEqmSoForecastInfo(eqmInfoSearchReqDto);
        List<Long> ids = eqmInfoSearchRespDtos.stream().map(EqmInfoSearchRespDto::getId).collect(toList());
        List<EqmInfoForecastRespDto> forecastRespDtoList = new ArrayList<>(16);
        List<EqmInfoRequirementRespDto> requirementRespDtos = new ArrayList<>(16);
        List<EqmInfoScnRespDto> scnRespDtos = new ArrayList<>(16);

        Map<Long, List<EqmInfoForecastRespDto>> forecastMap = new HashMap<>(16);
        Map<Long, List<EqmInfoRequirementRespDto>> requirementMap = new HashMap<>(16);
        Map<Long, List<EqmInfoScnRespDto>> scnMap = new HashMap<>(16);

        if (CollectionUtils.isEmpty(ids)) {
            return CommonResult.success(Collections.emptyList());
        }
        LambdaQueryWrapperX<SoForecastDO> lambdaQueryWrapperX = new LambdaQueryWrapperX<>();
        lambdaQueryWrapperX.inIfPresent(SoForecastDO::getSoId, ids);
        List<SoForecastDO> doList = soForecastMapper.selectList(lambdaQueryWrapperX);

        if (CollectionUtils.isNotEmpty(doList)) {
            forecastRespDtoList = doList.stream().map(item -> {
                EqmInfoForecastRespDto forecastRespDto = new EqmInfoForecastRespDto();
                forecastRespDto.setCntrQuantity(item.getCntrQuantity());
                forecastRespDto.setCntrSize(item.getCntrSize());
                forecastRespDto.setCntrType(item.getCntrType());
                forecastRespDto.setSoId(item.getSoId());
                return forecastRespDto;
            }).collect(toList());
            forecastMap = forecastRespDtoList.stream().collect(groupingBy(EqmInfoForecastRespDto::getSoId));
        }

        LambdaQueryWrapperX<RequirementsDO> requirementsDoLambdaQueryWrapperX = new LambdaQueryWrapperX<>();
        requirementsDoLambdaQueryWrapperX.inIfPresent(RequirementsDO::getReferenceId, ids).eq(RequirementsDO::getReferenceType, SoSiEnum.SO.getValue()).eq(RequirementsDO::getRequireTypeCode, RequireTypeCodeEnum.PACKINGREQUEST.getValue());
        List<RequirementsDO> requirementsDoList = requirementsMapper.selectList(requirementsDoLambdaQueryWrapperX);
        if (CollectionUtils.isNotEmpty(requirementsDoList)) {
            requirementRespDtos = requirementsDoList.stream().map(item -> {
                EqmInfoRequirementRespDto requirementRespDto = new EqmInfoRequirementRespDto();
                requirementRespDto.setRequireCode(item.getRequireCode());
                requirementRespDto.setRequireRemark(item.getRequireRemark());
                requirementRespDto.setSoId(item.getReferenceId());
                return requirementRespDto;
            }).collect(toList());
            requirementMap = requirementRespDtos.stream().collect(groupingBy(EqmInfoRequirementRespDto::getSoId));
        }

        LambdaQueryWrapperX<SoScnDO> soScnDoLambdaQueryWrapperX = new LambdaQueryWrapperX<>();
        soScnDoLambdaQueryWrapperX.inIfPresent(SoScnDO::getSoId);
        List<SoScnDO> scnDoList = soScnMapper.selectList(soScnDoLambdaQueryWrapperX);
        if (CollectionUtils.isNotEmpty(scnDoList)) {
            scnRespDtos = scnDoList.stream().map(item -> {
                EqmInfoScnRespDto eqmSoInfoScnRespDto = new EqmInfoScnRespDto();
                eqmSoInfoScnRespDto.setCsmCode(item.getCsmCode());
                eqmSoInfoScnRespDto.setCompanyName(item.getCompanyName());
                eqmSoInfoScnRespDto.setPartyTypeCode(item.getPartyTypeCode());
                eqmSoInfoScnRespDto.setSoId(item.getSoId());
                return eqmSoInfoScnRespDto;
            }).collect(toList());
            scnMap = scnRespDtos.stream().collect(groupingBy(EqmInfoScnRespDto::getSoId));
        }
        for (EqmInfoSearchRespDto respDto : eqmInfoSearchRespDtos) {
            respDto.setDgFlag(false);
            if (CargoTypeEnum.DG.getValue().equalsIgnoreCase(respDto.getCargoType())) {
                respDto.setDgFlag(true);
            }
            respDto.setForecastRespDtoList(forecastMap.getOrDefault(respDto.getId(), Collections.emptyList()));
            respDto.setScnRespDtos(scnMap.getOrDefault(respDto.getId(), Collections.emptyList()));
            respDto.setRequirementRespDtos(requirementMap.getOrDefault(respDto.getId(), Collections.emptyList()));
        }
        return CommonResult.success(eqmInfoSearchRespDtos);
    }

    @Override
    public CommonResult<List<EqmInfoSearchRespDto>> searchImForecastInfo(EqmInfoSearchReqDto eqmInfoSearchReqDto) {
        if (StringUtil.isEmpty(eqmInfoSearchReqDto.getPodCode())) {
            throw ServiceExceptionUtil.exception(EqmErrorConstant.EQM_POD_NOT_ALLOW_NULL);
        }
        List<EqmInfoSearchRespDto> eqmInfoSearchRespDtos = blnoMapper.rpcEqmSearchBlnoInfo(eqmInfoSearchReqDto);
        List<Long> ids = eqmInfoSearchRespDtos.stream().map(EqmInfoSearchRespDto::getId).collect(toList());
        List<EqmInfoForecastRespDto> forecastRespDtoList = new ArrayList<>(16);
        List<EqmInfoScnRespDto> scnRespDtos = new ArrayList<>(16);

        Map<Long, List<EqmInfoForecastRespDto>> forecastMap = new HashMap<>(16);
        Map<String, List<EqmInfoRequirementRespDto>> requirementMap = new HashMap<>(16);
        Map<Long, List<EqmInfoScnRespDto>> scnMap = new HashMap<>(16);

        if (CollectionUtils.isEmpty(ids)) {
            return CommonResult.success(Collections.emptyList());
        }
        //查询箱信息
        LambdaQueryWrapperX<BlnoCntrDO> cntrDoLambdaQueryWrapperX = new LambdaQueryWrapperX<>();
        cntrDoLambdaQueryWrapperX.inIfPresent(BlnoCntrDO::getBlnoId, ids);
        List<BlnoCntrDO> blnoCntrDoList = blnoCntrMapper.selectList(cntrDoLambdaQueryWrapperX);
        if (CollectionUtils.isNotEmpty(blnoCntrDoList)) {
            forecastRespDtoList = blnoCntrDoList.stream().map(item -> {
                EqmInfoForecastRespDto eqmInfoForecastRespDto = new EqmInfoForecastRespDto();
                eqmInfoForecastRespDto.setCntrNo(item.getCntrNo());
                eqmInfoForecastRespDto.setCntrType(item.getCntrType());
                eqmInfoForecastRespDto.setCntrOwner(item.getCntrOwner());
                eqmInfoForecastRespDto.setCntrSize(item.getCntrSize());
                eqmInfoForecastRespDto.setCntrQuantity(Long.valueOf(item.getQuantity()));
                eqmInfoForecastRespDto.setBlId(item.getBlnoId());
                return eqmInfoForecastRespDto;
            }).collect(toList());
            forecastMap = forecastRespDtoList.stream().collect(groupingBy(EqmInfoForecastRespDto::getBlId));
        }
        //处理订舱要求
        List<String> blNos = eqmInfoSearchRespDtos.stream().map(EqmInfoSearchRespDto::getBlno).collect(toList());
        List<EqmInfoRequirementRespDto> soRequirementInfo = soMapper.getSoRequirementInfo(RequireTypeCodeEnum.PACKINGREQUEST.getValue(), blNos);
        requirementMap = soRequirementInfo.stream().collect(groupingBy(EqmInfoRequirementRespDto::getBookIngNo));
        //处理收发通
        LambdaQueryWrapperX<BlnoScnDO> scnDoLambdaQueryWrapperX = new LambdaQueryWrapperX<>();
        scnDoLambdaQueryWrapperX.inIfPresent(BlnoScnDO::getBlnoId, ids);
        List<BlnoScnDO> blnoScnDoList = blnoScnMapper.selectList(scnDoLambdaQueryWrapperX);
        if (CollectionUtils.isNotEmpty(blnoScnDoList)) {
            scnRespDtos = blnoScnDoList.stream().map(item -> {
                EqmInfoScnRespDto eqmInfoScnRespDto = new EqmInfoScnRespDto();
                eqmInfoScnRespDto.setBlNoId(item.getBlnoId());
                eqmInfoScnRespDto.setCsmCode(item.getCsmCode());
                eqmInfoScnRespDto.setCompanyName(item.getCompanyName());
                eqmInfoScnRespDto.setPartyTypeCode(item.getPartyTypeCode());
                return eqmInfoScnRespDto;
            }).collect(toList());
            scnMap = scnRespDtos.stream().collect(groupingBy(EqmInfoScnRespDto::getBlNoId));
        }
        for (EqmInfoSearchRespDto respDto : eqmInfoSearchRespDtos) {
            respDto.setDgFlag(false);
            if (CargoTypeEnum.DG.getValue().equalsIgnoreCase(respDto.getCargoType())) {
                respDto.setDgFlag(true);
            }
            respDto.setForecastRespDtoList(forecastMap.getOrDefault(respDto.getId(), Collections.emptyList()));
            respDto.setScnRespDtos(scnMap.getOrDefault(respDto.getId(), Collections.emptyList()));
            respDto.setRequirementRespDtos(requirementMap.getOrDefault(respDto.getBookingNo(), Collections.emptyList()));
        }

        return CommonResult.success(eqmInfoSearchRespDtos);
    }

    @Override
    public CommonResult<EqmVoyInfoRespDto> searchVoyInfo(EqmVoyInfoReqDto voyInfoReqDto) {
        List<EqmVoyInfoRespDto> eqmVoyInfoRespDtos = new ArrayList<>(8);
        if (ExImTypeEnum.EX.getValue().equalsIgnoreCase(voyInfoReqDto.getImExType())) {
            eqmVoyInfoRespDtos = blnoMapper.rpcEqmSearchExVoyInfo(voyInfoReqDto);
        } else {
            eqmVoyInfoRespDtos = blnoMapper.rpcEqmSearchImVoyInfo(voyInfoReqDto);
        }
        if (CollectionUtils.isNotEmpty(eqmVoyInfoRespDtos)) {
            return CommonResult.success(eqmVoyInfoRespDtos.get(0));
        } else {
            return CommonResult.success();
        }
    }

    @Override
    public CommonResult<EqmBlInfoRespDto> searchBlInfo(String blNo, String pol) {
        EqmBlInfoRespDto eqmBlInfoRespDto = new EqmBlInfoRespDto();
        List<EqmBlInfoRespDto> eqmBlInfoRespDtos = blnoMapper.rpcEqmBlInfo(blNo, pol);
        if (CollectionUtils.isNotEmpty(eqmBlInfoRespDtos)) {
            //处理订舱要求
            Map<String, List<EqmInfoRequirementRespDto>> requirementMap = new HashMap<>(16);
            List<String> blNos = eqmBlInfoRespDtos.stream().map(EqmBlInfoRespDto::getBlNo).collect(toList());
            List<EqmInfoRequirementRespDto> soRequirementInfo = soMapper.getSoRequirementInfo(RequireTypeCodeEnum.PACKINGREQUEST.getValue(), blNos);
            requirementMap = soRequirementInfo.stream().collect(groupingBy(EqmInfoRequirementRespDto::getBookIngNo));
            eqmBlInfoRespDto = eqmBlInfoRespDtos.get(0);
            eqmBlInfoRespDto.setEqmInfoRequirementRespDtos(requirementMap.getOrDefault(eqmBlInfoRespDto.getBookingNo(), Collections.emptyList()));
        }
        return CommonResult.success(eqmBlInfoRespDto);
    }

    @Override
    public CommonResult<List<EqmFreeTimeRespDto>> searchFreeTimeInfo(List<String> blnos) {
        List<EqmFreeTimeRespDto> eqmFreeTimeRespDtos = new ArrayList<>(32);
        LambdaQueryWrapperX<BlnoDO> blnoLambdaQueryWrapperX = new LambdaQueryWrapperX<>();
        blnoLambdaQueryWrapperX.eq(BlnoDO::getPodBlFlag, true)
                .eq(BlnoDO::getValid, SiValidEnum.VALID.getValue())
                .in(BlnoDO::getBlNo, blnos);
        List<BlnoDO> blnoDos = blnoMapper.selectList(blnoLambdaQueryWrapperX);
        if (CollectionUtils.isEmpty(blnoDos)) {
            return CommonResult.success(Collections.emptyList());
        }
        List<Long> ids = blnoDos.stream().map(BlnoDO::getId).collect(toList());
        //查询箱信息
        LambdaQueryWrapperX<BlnoCntrDO> cntrDoLambdaQueryWrapperX = new LambdaQueryWrapperX<>();
        cntrDoLambdaQueryWrapperX.inIfPresent(BlnoCntrDO::getBlnoId, ids);
        List<BlnoCntrDO> blnoCntrDoList = blnoCntrMapper.selectList(cntrDoLambdaQueryWrapperX);
        Map<Long, List<BlnoCntrDO>> cntrMapList = blnoCntrDoList.stream().collect(groupingBy(BlnoCntrDO::getBlnoId));
        //处理收发通
        List<String> scnInfo = Arrays.asList(PartyTypeCodeEnum.SHIPPER.getValue(), PartyTypeCodeEnum.CONSIGNEE.getValue());
        LambdaQueryWrapperX<BlnoScnDO> scnDoLambdaQueryWrapperX = new LambdaQueryWrapperX<>();
        scnDoLambdaQueryWrapperX.inIfPresent(BlnoScnDO::getBlnoId, ids)
                .in(BlnoScnDO::getPartyTypeCode, scnInfo);
        List<BlnoScnDO> blnoScnDoList = blnoScnMapper.selectList(scnDoLambdaQueryWrapperX);
        Map<Long, List<BlnoScnDO>> scnMapList = blnoScnDoList.stream().collect(groupingBy(BlnoScnDO::getBlnoId));
        //查询vslvoyinfo只查询第一段的
        LambdaQueryWrapperX<BlnoVslvoyDO> vslVeyInfoLambdaQueryWrapperX = new LambdaQueryWrapperX<>();
        vslVeyInfoLambdaQueryWrapperX.inIfPresent(BlnoVslvoyDO::getBlnoId, ids)
                .eq(BlnoVslvoyDO::getRouteNo, 1);
        List<BlnoVslvoyDO> vslvoyDoList = blnoVslvoyMapper.selectList(vslVeyInfoLambdaQueryWrapperX);
        Map<Long, BlnoVslvoyDO> vslVoyMap = vslvoyDoList.stream().collect(Collectors.toMap(BlnoVslvoyDO::getBlnoId, item -> item, (ex, rp) -> rp));

        //查询货物信息
        LambdaQueryWrapperX<BlnoCargoDO> cargoDoLambdaQueryWrapperX = new LambdaQueryWrapperX<>();
        cargoDoLambdaQueryWrapperX.in(BlnoCargoDO::getBlnoId, ids);
        List<BlnoCargoDO> blnoCargoDos = blnoCargoMapper.selectList(cargoDoLambdaQueryWrapperX);
        Map<Long, BlnoCargoDO> cargoMap = blnoCargoDos.stream().collect(Collectors.toMap(BlnoCargoDO::getBlnoId, item -> item, (ex, rp) -> rp));


        List<FreeTimeReqVo> freeTimeRegvos = new ArrayList<>(32);
        for (BlnoDO blnoDo : blnoDos) {
            List<CalFrtRateUnitReqVo> rateUnits = new ArrayList<>(256);
            FreeTimeReqVo freeTimeReqVo = new FreeTimeReqVo();
            List<BlnoCntrDO> cntrs = cntrMapList.get(blnoDo.getId());
            List<BlnoScnDO> scn = scnMapList.get(blnoDo.getId());
            String consigneeCode = "";
            String shipperCode = "";
            if (CollectionUtils.isEmpty(scn)) {
                for (BlnoScnDO blnoScnDo : scn) {
                    if (PartyTypeCodeEnum.SHIPPER.getValue().equals(blnoScnDo.getPartyTypeCode())) {
                        shipperCode = blnoScnDo.getCsmCode();
                    }
                    if (PartyTypeCodeEnum.CONSIGNEE.getValue().equals(blnoScnDo.getPartyTypeCode())) {
                        consigneeCode = blnoScnDo.getCsmCode();
                    }
                }
            }
            BlnoVslvoyDO blnoVslvoyDo = vslVoyMap.get(blnoDo.getId());
            boolean flag = null == blnoVslvoyDo ||
                    StringUtil.isEmpty(blnoVslvoyDo.getVesselCode()) ||
                    StringUtil.isEmpty(blnoVslvoyDo.getVoyageEx()) ||
                    StringUtil.equals(TBA, blnoVslvoyDo.getVesselCode()) ||
                    StringUtil.equals(TBA, blnoVslvoyDo.getVoyageEx());
            if (flag) {
                return CommonResult.error(new ErrorCode(500, BARGE_ERROR));
            }
            LocalDateTime localDateTime = null;
            //判断是多式联运还是单程 flag=false时多式联运
            if (StringUtil.equals(blnoVslvoyDo.getTransmode(), TransmodeEnum.LINER.getValue())) {
                localDateTime = costChargeUtil.getBusinessDate(blnoVslvoyDo.getPolCode(), blnoVslvoyDo.getVoyageEx(), blnoVslvoyDo.getLaneCodeEx(), Arrays.asList(blnoVslvoyDo.getVesselCode()));
            } else {
                String transmode = TransmodeEnum.getBargeTypeByValue(blnoVslvoyDo.getTransmode());
                BargeQueryReqDTO bargeQueryReqDto = new BargeQueryReqDTO();
                bargeQueryReqDto.setPortCode(blnoVslvoyDo.getPolCode());
                bargeQueryReqDto.setTransportCode(transmode);
                bargeQueryReqDto.setExVoy(blnoVslvoyDo.getVoyageEx());
                LocalDate localDate = voyScheduleService.multiBargeSchedule(bargeQueryReqDto);
                if (null == localDate) {
                    return CommonResult.error(new ErrorCode(500, SCHEDULE_ERROR));
                }
                localDateTime = localDate.atStartOfDay();
            }
            BlnoCargoDO blnoCargoDo = cargoMap.get(blnoDo.getId());
            for (BlnoCntrDO blnoCntrDo : cntrs) {
                CalFrtRateUnitReqVo calFrtRateUnitReqVo = new CalFrtRateUnitReqVo();
                calFrtRateUnitReqVo.setCntrSizeType(blnoCntrDo.getCntrSize() + blnoCntrDo.getCntrType());
                calFrtRateUnitReqVo.setCntrSize(Integer.valueOf(blnoCntrDo.getCntrSize()));
                calFrtRateUnitReqVo.setCntrType(blnoCntrDo.getCntrType());
                calFrtRateUnitReqVo.setCargoType(blnoCargoDo.getCargoType());
                rateUnits.add(calFrtRateUnitReqVo);
            }
            freeTimeReqVo.setAgreementNo(blnoDo.getAgreementNo());
            freeTimeReqVo.setBlno(blnoDo.getBlNo());
            freeTimeReqVo.setConsigneeCode(consigneeCode);
            freeTimeReqVo.setShipperCode(shipperCode);
            freeTimeReqVo.setBusinessDate(localDateTime);
            freeTimeReqVo.setRateUnits(rateUnits);
            freeTimeRegvos.add(freeTimeReqVo);
        }
        eqmFreeTimeRespDtos = mktService.queryFreeTime(freeTimeRegvos);
        return CommonResult.success(eqmFreeTimeRespDtos);
    }
}
